package modelo.delictivas;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import modelo.caracteristicas.Cabello;
import modelo.caracteristicas.Hobby;
import modelo.caracteristicas.ICaracteristica;
import modelo.caracteristicas.Senia;
import modelo.caracteristicas.Sexo;
import modelo.caracteristicas.Vehiculo;
import modelo.delictivas.TesoroNacional;
import modelo.geografia.Capital;
import modelo.geografia.Coordenada;
import modelo.geografia.Mapa;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;



public class Ladron {

	private String nombre;
	private Capital capitalActual;
	private int paisesDeEscapeConTesoroComun;
	private int paisesDeEscapeConTesoroValioso;
	private int paisesDeEscapeConTesoroMuyValioso;
	private Cabello cabello = Cabello.CASTANIO;
	private Vehiculo vehiculo = Vehiculo.DEPORTIVO;
	private Hobby hobby = Hobby.ALPINISMO;
	private Senia senia = Senia.ANILLO;
	private Sexo sexo = Sexo.FEMENINO;

	public Ladron(String nombre) {
		this.nombre = nombre;
		this.paisesDeEscapeConTesoroComun = 4;
		this.paisesDeEscapeConTesoroValioso = 5;
		this.paisesDeEscapeConTesoroMuyValioso = 7;
		this.setCapitalActual( new Capital ( "SinCapital", new Coordenada(0,0) ) );
	}

	private void setCapitalActual(Capital capital){
		
		this.capitalActual = capital;
		
	}
	
	public String getNombre() {
		return this.nombre;
	}

	public Capital getCapitalActual() {
		
		return ( this.capitalActual );
	}
	
	public void viajar(Capital capitalDestino) throws Exception {
		
		if(this.capitalActual == null)
			throw new Exception("El ladron debe robar un tesoro para localizarse en una capital inicial");
		if(this.capitalActual.obtenerDistanciaACapital(capitalDestino) == 0)
			throw new Exception("El ladron intenta viajar al mismo pais donde se encuentra");
		this.capitalActual.dejarRastroHaciaCapitalDestino(capitalDestino.getRastro());
		this.capitalActual.agregarCaracteristicaAPistasDeUnEstablecimiento(this.getCaracteristicaAlAzar());
		this.capitalActual = capitalDestino;

	}
	
	private ICaracteristica getCaracteristicaAlAzar() {
		
		ICaracteristica devolucion = null;
		Random randomGenerator = new Random();
		switch (randomGenerator.nextInt(4)) {
		
			case 0: 
				devolucion = this.cabello;
				break;
			
			case 1: 	
				devolucion = this.vehiculo;
				break;
			
			case 2: 
				devolucion = this.senia;
				break;
			
			case 3: 
				devolucion = this.hobby;
				break;
		}
		return devolucion;
	}

	public int getCantidadDePaisesConTesoroComun(){
		
		return this.paisesDeEscapeConTesoroComun;	
	}
	
	public int getCantidadDePaisesConTesoroValioso(){
		
		return this.paisesDeEscapeConTesoroValioso;	
	}
	
	public int getCantidadDePaisesConTesoroMuyValioso(){
		
		return this.paisesDeEscapeConTesoroMuyValioso;	
	}
	
	public Robo robarTesoro(TesoroNacional tesoro) throws Exception{
		
		this.capitalActual = tesoro.getCapitalDeOrigen();
		return new Robo(tesoro, this);
		
	}
	
	private void esconderseEnCapital(){
		
		this.capitalActual.esconderLadronEnCapital();
		this.capitalActual.dejarTrampasEnCapital( this.generarTrampas() );

	}
	
	private List<ITrampa> generarTrampas() {
		
		List<ITrampa> trampas = new ArrayList<ITrampa> ();
		trampas.add(new Cuchillazo());
		trampas.add(new Disparo());
		return trampas;
	}

	public List<Capital> generarRutaDeEscapeAlRobarTesoro(TesoroNacional unTesoro) throws Exception{
		
		List<Capital> escape = new ArrayList<Capital>();
		
		escape.add( this.capitalActual );
		int cantidad = unTesoro.obtenerCantidadCapitalesAEscaparse(this);
		
		for(int i = 0; i < cantidad ; i++) {
			
			Capital capitalSiguiente = this.obtenerCapitalSiguiente(escape);
			escape.add( capitalSiguiente );			
			this.viajar(capitalSiguiente);
		 }
		 this.esconderseEnCapital();
		return escape;
	}
	
	private Capital obtenerCapitalSiguiente(List<Capital> escape) throws Exception{
		
		List<Capital> capitalesCandidatas = new ArrayList<Capital>();
		capitalesCandidatas.addAll(this.capitalActual.getCapitalesConectadas());
		
		Random randomGenerator = new Random();
		//Para obtener una capital aleatoria
		
		Capital capitalCandidata;
		Boolean candidataYaVisitada=true;
		int i;
		do {
			if(capitalesCandidatas.isEmpty())
				throw new Exception("No se pudo realizar escape del ladron, no hay suficientes capitales o conexiones.");
			
			i = randomGenerator.nextInt( ( capitalesCandidatas.size() ));
			capitalCandidata = capitalesCandidatas.get(i);
			candidataYaVisitada = false;
			
			if(escape.contains(capitalCandidata))
			{
				candidataYaVisitada = true;
				capitalesCandidatas.remove(capitalCandidata);
			}
			
		} while (candidataYaVisitada);
		
		return capitalCandidata;
	}

	public void setColorDeCabello(Cabello caracteristica) {
		
		cabello = caracteristica;		
	}

	public void setVehiculo(Vehiculo caracteristica) {
		
		vehiculo = caracteristica;		
	}

	public void setSexo(Sexo caracteristica) {
		
		sexo = caracteristica;		
	}
	
	public void setHobby(Hobby caracteristica) {
		
		hobby = caracteristica;		
	}
	
	public void setSenia(Senia caracteristica) {
		
		senia = caracteristica;		
	}
	
	public ICaracteristica getColorDeCabello() {
		
		return this.cabello;		
	}

	public ICaracteristica getVehiculo() {
		
		return this.vehiculo;		
	}

	public ICaracteristica getSexo() {
		
		return this.sexo;		
	}
	
	public ICaracteristica getHobby() {
		
		return this.hobby;		
	}
	
	public ICaracteristica getSenia() {
		
		return this.senia;		
	}
	
	
	
	public Node serializar(Document doc) {
		
		Element elementoLadron = doc.createElement("Ladron");
		elementoLadron.setAttribute("Nombre", this.nombre);
		
		Element elementoCaracteristicas = doc.createElement("Caracteristicas");
		
		elementoCaracteristicas.setAttribute("Cabello", this.cabello.name());
		
		elementoCaracteristicas.setAttribute("Vehiculo", this.vehiculo.name());
		
		elementoCaracteristicas.setAttribute("Hobby", this.hobby.name());
		
		elementoCaracteristicas.setAttribute("Senia", this.senia.name());
		
		elementoCaracteristicas.setAttribute("Sexo", this.sexo.name());
		
		elementoLadron.appendChild(elementoCaracteristicas);
		
		//Element elementoCapitalActual = doc.createElement("CapitalActual");
		//elementoCapitalActual.appendChild(this.capitalActual.serializar(doc));
		//elementoLadron.appendChild(elementoCapitalActual);
		elementoLadron.setAttribute("capitalActual", this.capitalActual.getNombre());
		
		return elementoLadron;
	}

	public static Ladron hidratar(Element elementoLadron) throws Exception {
		
		
		String nombre = ((Element)elementoLadron).getAttribute("Nombre");
		Ladron nuevoLadron = new Ladron (nombre);
		
		Element elementoCaracteristicas = (Element) elementoLadron.getElementsByTagName("Caracteristicas").item(0);
		
		String descripcionCabello = elementoCaracteristicas.getAttribute("Cabello");
		nuevoLadron.setColorDeCabello(Cabello.valueOf(descripcionCabello));
		
		String descripcionVehiculo = elementoCaracteristicas.getAttribute("Vehiculo");
		nuevoLadron.setVehiculo(Vehiculo.valueOf(descripcionVehiculo));
		
		String descripcionSenia = elementoCaracteristicas.getAttribute("Senia");
		nuevoLadron.setSenia(Senia.valueOf(descripcionSenia));
		
		String descripcionSexo = elementoCaracteristicas.getAttribute("Sexo");
		nuevoLadron.setSexo(Sexo.valueOf(descripcionSexo));
		
		String descripcionHobby = elementoCaracteristicas.getAttribute("Hobby");
		nuevoLadron.setHobby(Hobby.valueOf(descripcionHobby));
		
		//Element elementoCapital = (Element) elementoLadron.getElementsByTagName("CapitalActual").item(0);
		
		Capital origen = Mapa.obtenerMapa().obtenerCapitalLlamada(elementoLadron.getAttribute("capitalActual"));
		//Capital origen = Capital.hidratar ( (Element) elementoCapital.getElementsByTagName("Capital").item(0) );
		nuevoLadron.setCapitalActual(origen);
		
		return nuevoLadron;
	}
	
	
}
